/*
 * SwingImageDelegate.cpp  0.4.0 / Nov 17, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "SwingImageDelegate.h"

// SwingImageDelegate :: Static Native Calls. ----------------------------------

/*!
 * \brief Creates new image.
 *
 * \param env the JNIEnv pointer
 *
 * \return image pointer
 */
jlong SwingImageDelegate::createImage(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_STATIC_REENTRANT_RETURN(SwingImageDelegate, createImage, jlong,
                                SWING_ENV_ARG)
  return reinterpret_cast<jlong>(new QPixmap());
}

/*!
 * \brief Creates new image.
 *
 * \param env the JNIEnv pointer
 * \param obj the Swing image object
 * \param imageData the image data
 * \param lenght the lenght of the image data
 *
 * \return image pointer
 */
jlong SwingImageDelegate::createImage(JNIEnv *env, jobject obj,
                                      jbyteArray imageData, jint lenght)
{
  Q_ASSERT(env);
  Q_ASSERT(obj);
  SWING_STATIC_REENTRANT_RETURN(SwingImageDelegate, createImageOBAI, jlong,
                                SWING_ENV_ARG, JOBJECT_ARG(obj),
                                JBYTEARRAY_ARG(imageData), JINT_ARG(lenght))
  if (imageData) {
    Q_ASSERT(lenght > 0);
    QPixmap *pixmap = new QPixmap();
    uchar *bytes = (uchar *)env->GetPrimitiveArrayCritical(imageData, 0);
    bool loadSucceed = pixmap->loadFromData(bytes, lenght);
    env->ReleasePrimitiveArrayCritical(imageData, bytes, JNI_ABORT);
    if (loadSucceed) {
      JNIWrapper::setIntField(env, obj, sm_widthFID, pixmap->width());
      JNIWrapper::setIntField(env, obj, sm_heightFID, pixmap->height());
      return reinterpret_cast<jlong>(pixmap);
    }
    delete pixmap;
  }
  return 0;
}

/*!
 * \brief Creates new image.
 *
 * \param env the JNIEnv pointer
 * \param imagePointer the pointer of the original image
 * \param width the new image width
 * \param height the new image height
 * \param hints the transformation hints
 * \param format the format
 *
 * \return pointer of the scaled image
 */
jobject SwingImageDelegate::createScaled(JNIEnv *env, jlong imagePointer,
                                         jint width, jint height, jint hints,
                                         jstring format)
{
  Q_ASSERT(env);
  SWING_STATIC_REENTRANT_RETURN(SwingImageDelegate, createScaled, jobject,
                                SWING_ENV_ARG, JLONG_ARG(imagePointer),
                                JINT_ARG(width), JINT_ARG(height),
                                JINT_ARG(hints), JSTRING_ARG(format))
  if (imagePointer) {
    QPixmap *pixmap = reinterpret_cast<QPixmap *>(imagePointer);
    Qt::TransformationMode transformMode;
    if (hints == 4) {
      transformMode = Qt::SmoothTransformation;
    } else {
      transformMode = Qt::FastTransformation;
    }
    return newInstance(pixmap->scaled(width, height,
                                      Qt::IgnoreAspectRatio, transformMode),
                       format);
  }
  return 0;
}

/*!
 * \brief Initializes SwingImageDelegate class.
 *
 * \param env the JNIEnv pointer 
 * \param cls the SwingGraphics class
 */
void SwingImageDelegate::initialize(JNIEnv *env, jclass cls)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(!sm_imageClass);
  if (!INIT_CLASS(image, cls) ||
      !INIT_CONSTRUCTOR(constructor, cls, "(J[BII)V") ||
      !INIT_UFID(width, cls, "I") || !INIT_UFID(height, cls, "I")) {
    FATAL_LOGGED_ERROR("SwingImageDelegate initialization failed");
  }
}

// SwingImageDelegate :: Public Static Member Functions. -----------------------

/*!
 * \brief Creates Swing image from specified QPixmap.
 *
 * \param pixmap the pixmap
 * \param format the image format
 *
 * \return Swing image
 */
jobject SwingImageDelegate::newInstance(const QPixmap &pixmap, jstring format)
{
  JNIEnv *env = JNISwingWrapper::env();
  const char *imageFormat = env->GetStringUTFChars(format, 0);
  if (imageFormat) {
    QByteArray bytes;
    QBuffer buffer(&bytes);
    buffer.open(QIODevice::WriteOnly);
    if (pixmap.save(&buffer, imageFormat)) {
      int length = buffer.size();
      jbyteArray byteArray = JNIWrapper::newByteArray(env, length);
      if (byteArray) {
        QPixmap *imagePixmap = new QPixmap(pixmap);
        env->SetByteArrayRegion(byteArray, 0, length,
                        reinterpret_cast<const jbyte *>(bytes.constData()));
        jobject image = JNIWrapper::newObject(env, sm_imageClass,
                        sm_constructorMID, reinterpret_cast<jlong>(imagePixmap),
                        byteArray, pixmap.width(), pixmap.height());
        if (!image) {
          delete imagePixmap;
        }
        env->DeleteLocalRef(byteArray);
        return image;
      }
    }
    env->ReleaseStringUTFChars(format, imageFormat);
  }
  return 0;
}

/*!
 * \brief Creates new disabled Pixmap from the specified Pixmap.
 *
 * \param pm the QPixmap 
 *
 * \return new disabled QPixmap
 */
QPixmap *SwingImageDelegate::createDisabledPixmap(QPixmap *pm)
{
  if (pm) {
    QStyleOption opt(0);
    opt.palette = QApplication::palette();
    return new QPixmap(
        QApplication::style()->generatedIconPixmap(QIcon::Disabled, *pm, &opt));

  }
  return 0;
}

/*!
 * \brief Loads image.
 *
 * \param env the JNIEnv pointer
 * \param imageData the image data
 * \param length the image data length
 * \param pixmap the pixmap
 *
 * \return \c true if succeed
 */
bool SwingImageDelegate::loadImage(JNIEnv *env, jbyteArray imageData,
                                   jint length, QPixmap *pixmap)
{
  uchar *bytes =
       reinterpret_cast<uchar *>(env->GetPrimitiveArrayCritical(imageData, 0));
  bool loadSucceed = pixmap->loadFromData(bytes, length);
  env->ReleasePrimitiveArrayCritical(imageData, bytes, JNI_ABORT);
  return loadSucceed;
}

// SwingImageDelegate :: Private Static Data Members. --------------------------

jclass SwingImageDelegate::sm_imageClass = 0;
jmethodID SwingImageDelegate::sm_constructorMID = 0;
jfieldID SwingImageDelegate::sm_widthFID = 0;
jfieldID SwingImageDelegate::sm_heightFID = 0;
